package com.lzx.applib.widget.image.imageview_attacher;

import android.animation.Animator;
import android.animation.AnimatorListenerAdapter;
import android.animation.AnimatorSet;
import android.animation.ObjectAnimator;
import android.animation.ValueAnimator;
import android.animation.ValueAnimator.AnimatorUpdateListener;
import android.annotation.SuppressLint;
import android.content.Context;
import android.view.GestureDetector;
import android.view.Gravity;
import android.view.MotionEvent;
import android.view.ScaleGestureDetector;
import android.view.View;
import android.view.View.OnClickListener;
import android.view.View.OnLongClickListener;
import android.view.View.OnTouchListener;
import android.view.ViewGroup;
import android.view.ViewParent;
import android.view.ViewTreeObserver.OnGlobalLayoutListener;
import android.widget.FrameLayout;
import android.widget.ImageView;
import android.widget.ImageView.ScaleType;

import com.lzx.applib.utils.LogUtil;


public class ImageViewAttacher  implements OnGlobalLayoutListener{
	
	ImageView img;
	Context context;
	
	private GestureDetector gestureDetector;
	private ScaleGestureDetector scaleGestureDetector;
	
	private OnClickListener onClickListener;
	private OnLongClickListener onLongClickListener;
	
	private MScaleListener mScaleListener;
	
	private ViewParent parent;
	private boolean hasEdge = true;
	
	public ImageViewAttacher(ImageView imageView, boolean hasEdge) {
		this.img = imageView;
		this.context = img.getContext();
		this.hasEdge = hasEdge;
		
		setUpImageView();
		
		gestureDetector = new GestureDetector(context, new MGestureListener(context, this));
		gestureDetector.setOnDoubleTapListener(new MDoubleTapListener(this));

		mScaleListener = new MScaleListener(this);
		scaleGestureDetector= new ScaleGestureDetector(context, mScaleListener);
		
		parent = img.getParent();
		parent.requestDisallowInterceptTouchEvent(true);
		
		((View)parent).setOnTouchListener(new OnTouchListener() {

			@Override
			public boolean onTouch(View v, MotionEvent event) {
				// TODO Auto-generated method stub
				gestureDetector.onTouchEvent(event);
				scaleGestureDetector.onTouchEvent(event);
				return true;
			}
		});
		
		img.getViewTreeObserver().addOnGlobalLayoutListener(this);
	}
	
	public ImageViewAttacher(ImageView imageView) {
		this(imageView, true);
	}

	public void attachClickListener(OnClickListener listener) {
		this.onClickListener = listener;
	}
	public void attachLongClickListener(OnLongClickListener listener) {
		this.onLongClickListener = listener;
	}
	
	void log(String msg) {
		LogUtil.e("ImageViewAttacher", msg);
	}

	@SuppressLint("NewApi")
	public void setScale(float f) {
		// TODO Auto-generated method stub
		log("Image Scale :" + f);
		img.setScaleX(f);
		img.setScaleY(f);
		
		move(0, 0);
		img.requestLayout();
		if(parent!=null)
			((View)parent).requestLayout();
	}

	public void rotateToLeft() {
		// TODO Auto-generated method stub
		rotate(90);
	}

	public void rotateToRight() {
		// TODO Auto-generated method stub
		rotate(-90);
	}

	@SuppressLint("NewApi")
	public void rotate(int degree) {
		img.setRotation(img.getRotation() + degree);
		img.setScaleY(1f);
		img.setScaleX(1f);
		img.setScrollX(0);
		img.setScrollY(0);
		img.setScaleType(ScaleType.FIT_CENTER);

//		if (parent != null) ((View)parent).invalidate();
	}

	@SuppressLint("NewApi")
	void move(float dx, float dy) {
		dx = dx/getScale();
		dy = dy/getScale();
		log("Luozexin move :" +dx+" "+photoWidth+" "+photoHeight+(int)(dx*photoWidth)+" "+(int)(dy*photoHeight));
		if (img.getScaleX() < 1) {
			return;
		}
		
		float temp = 0;
		float rotate = img.getRotation();
		if (rotate == 90f) {
			temp = dy;
			dy = -dx;
			dx = temp;
			System.out.println();
		} else if (rotate == 180f) {
			temp = dy;
			dy = -dx;
			dx = -temp;
			System.out.println();
		} else if (rotate == 270f) {
			temp = dy;
			dy = dx;
			dx = -temp;
			System.out.println();
		} else {
			System.out.println();
		}
		
		
		log(img.getScrollX() + ":" + img.getScrollY());
		
		boolean xMove = canXMove(dx);
		boolean yMove = canYMove(dy);
		img.scrollBy((int)(xMove?dx:0), (int)(yMove?dy:0));
		
		if (!xMove || !yMove) 
			if (parent != null) parent.requestDisallowInterceptTouchEvent(false);
		
//		if (parent != null) ((View)parent).invalidate();
	}

	
	final int ANIM_TIME = 200;
	@SuppressLint("NewApi") void anim(float fromX, final float toX, float fromY, final float toY, final float scale){
		ObjectAnimator animatorX = ObjectAnimator.ofFloat(img, "scaleX", fromX, toX);
		ObjectAnimator animatorY = ObjectAnimator.ofFloat(img, "scaleY", fromY, toY);
		animatorX.addUpdateListener(new AnimatorUpdateListener() {
			
			@Override
			public void onAnimationUpdate(ValueAnimator animation) {
				// TODO Auto-generated method stub
				move(0, 0);
			}
		});
		animatorX.addListener(new AnimatorListenerAdapter() {
			@Override
			public void onAnimationEnd(Animator animation) {
				move(0, 0);
			}
		});
		AnimatorSet set = new AnimatorSet();
		set.setDuration(ANIM_TIME).playTogether(animatorX, animatorY);
		set.start();
	}
	
	@SuppressLint("NewApi") public float getScale(){
		return img.getScaleX();
	}
	
	@SuppressLint("NewApi")
	public void reset(){
		img.setRotation(0);
		img.setScaleY(1f);
		img.setScaleX(1f);
		img.setScrollX(0);
		img.setScrollY(0);
		img.setScaleType(ScaleType.FIT_CENTER);
		
		cal();
	}
	
	public void scaleEnd() {
		mScaleListener.onScaleEnd(scaleGestureDetector);
	}

	public void setLarger() {
		// TODO Auto-generated method stub
		float scale = getScale();
		if (scale < MScaleListener.MAX_SCALE) {
			setScale(getScale()+0.1f);
		}
	}

	public void setSmaller() {
		// TODO Auto-generated method stub
		float scale = getScale();
		if (scale >1 ) {
			setScale(getScale()-0.1f);
		}
	}

	private int viewWidth, viewHeight;
	private int photoWidth,photoHeight;
	@Override
	public void onGlobalLayout() {
		// TODO Auto-generated method stub
		viewWidth = img.getWidth();
		viewHeight = img.getHeight();
		if (viewWidth > 0) {
			img.getViewTreeObserver().removeGlobalOnLayoutListener(this);
			cal();
		}
		
		log("Luozexin : onGlobalLayout:"+viewWidth +"  "+viewHeight );
	}
	
	private void cal(){
		photoWidth = img.getDrawable().getIntrinsicWidth();
		photoHeight = img.getDrawable().getIntrinsicHeight();

		log("Luozexin : cal1:"+photoWidth +"  "+photoHeight );
		float rW = viewWidth/(float)photoWidth;
		float rH = viewHeight/(float)photoHeight;
		
		float r = Math.min(rW, rH);
		
		
		photoWidth = (int) (r*photoWidth);
		photoHeight = (int) (r*photoHeight);

		halfPhotoW = photoWidth/2f;
		halfPhotoH = photoHeight/2f;
		
		halfViewH = viewHeight/2f;
		halfViewW = viewWidth/2f;
		
		log("Luozexin : cal1:"+photoWidth +"  "+photoHeight );
	}
	
	
	private float halfPhotoW, halfPhotoH;
	private float halfViewW, halfViewH;


	@SuppressLint("NewApi")
	private boolean canXMove(float dx) {
		if (!hasEdge) 
			return true;
		
		int sx = img.getScrollX();
		float scale = getScale();
		
		float sHW = (float) (halfViewW/scale);
		
		int MaxScroll =  Math.max(0, (int) (halfPhotoW - sHW));
		
		if (MaxScroll < Math.abs(sx+dx))
		{
			img.setScrollX(MaxScroll*(sx>0?1:-1));
			return false;
		}
		return true;
	}
	
	@SuppressLint("NewApi")
	private boolean canYMove(float dy) {
		if (!hasEdge) 
			return true;
		
		int sy = img.getScrollY();
		float scale = getScale();
		
		float sHH = (float) (halfViewH/scale);
		
		int MaxScroll = Math.max((int) (halfPhotoH - sHH), 0);
		
		if (MaxScroll < Math.abs(sy+dy)){
			img.setScrollY(MaxScroll*(sy>0?1:-1));
			return false;
		}
		return true;
	}

	
	void onLongPress() {
		if (onLongClickListener != null)
			onLongClickListener.onLongClick(img);
	}
	
	/**
	 * while single tap, just click the image
	 * */
	void onSingleTap() {
		if (onClickListener != null)
			onClickListener.onClick(img);
	}
	
	/**
	 * while double tap, just scale the image.
	 * */
	void onDoubleTap() {
		float max = MScaleListener.MAX_SCALE;
		float scale = getScale();
		float toScale = 1f;
		if (scale < max / 2)
			toScale = max / 2;
		else if (scale < max)
			toScale = max;

		anim(scale, toScale, scale, toScale, toScale);
	}
	
	private void setUpImageView() {
		ViewParent currentParent = img.getParent();
		if (currentParent!=null 
				&& currentParent instanceof ViewGroup) {
			ViewGroup.LayoutParams currentParams = img.getLayoutParams();
			
			FrameLayout.LayoutParams newParams;
			if (currentParams != null) {
				newParams = new FrameLayout.LayoutParams(currentParams);
			} else {
				int width = ViewGroup.LayoutParams.MATCH_PARENT;
				int height = ViewGroup.LayoutParams.MATCH_PARENT;
				int gravity = Gravity.CENTER_HORIZONTAL | Gravity.TOP;
				newParams = new FrameLayout.LayoutParams(width, height, gravity);
			}
			img.setLayoutParams(newParams);
			
			FrameLayout newParent = new FrameLayout(context);
			newParent.setLayoutParams(currentParams);
		
			int indexInParent = ((ViewGroup)currentParent).indexOfChild(img);
			((ViewGroup)currentParent).removeView(img);
			
			newParent.addView(img);
			((ViewGroup)currentParent).addView(newParent, indexInParent);
			
			parent = newParent;
		}
	}
}
